简介

由于在CC链的学习过程中,是使用的IO操作,模拟网络传输操作,在这里难免会不太理解如果是在web传输过程中,如何实现序列化数据在网络上传输,并且在网络传输过程中,序列化数据(二进制流)与源文件的hash值不等,以及文件特征丢失等等很奇怪的问题,目前找到原因就是编码问题,但是二进制流的会被篡改的问题还没有解决,但是在测试反序列化,就能知道有哪些需要注意的事项了

环境

jdk 8u181
maven 3.8.5
springmvc 4.3.18.RELEASE
tomcat 8.5.79

搭建SpringMVC

web选取SpringMVC,关于SpringMVC的搭建过程,请参考SpringMVC内存马#创建SpringMVC项目,Tomcat版本为8.5.79,目录结构如下所示

image.png

然后整体思路是,通过文件上传,上传已经序列化好的文件(可以通过ysoserial项目创建,也可以自己下载对应的Commons Collections包,进行序列化成文件) 为什么会用文件上传的形式?这个在后面提及,当然还有更好的方式,但是只是为了验证网络传输,所以也就选择了最简单的方式 但是文件上传需要用到中间件,依赖如下,添加到pom.xml中

<!--文件上传依赖包-->
<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
</dependency>

并且在dispatcher-servlet.xml里添加bean,配置上传文件的最大值,以及默认的编码方式

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
  <property name="maxUploadSize" value="10485760"/>
  <property name="defaultEncoding" value="UTF-8" />
</bean>

HelloController

/hi接口是返回前端的文件上传页面,/ysoserial接口则是处理传入的序列化的=数据,然后进行反序列化操作

package com.spring.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;

@Controller
public class HelloController {
    @RequestMapping(value = "/hi")
    public String ReturnJsp(){
        return "hello";
    }
    @RequestMapping(value = "/ysoserial")
    public String SerialTest(@RequestParam("file") MultipartFile f1) throws Exception{
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(f1.getBytes());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        return "test";
    }
}

启动起来,效果如下:

image.png

这里上传对应的已经序列化过后的文件(比如CC7.ser),即可执行命令

image.png

image.png

然后将它运行起来之后,就可以看到正常的网络传输过程中,在web中如何反序列化 这个靶场其实很简单,但是在其中的问题很多,所以才会有这一篇文章 在针对上传文件属实有点low了,这里将文件输出成base64编码,然后网络传输传递base64编码,然后再序列化

// Base64EncodeTest
package com.myproject;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class Base64EncodeTest {
    public static String encodeBase64File(String path) throws Exception{
        File file = new File(path);
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] buffer = new byte[(int) file.length()];
        fileInputStream.read(buffer);
        fileInputStream.close();
        return new BASE64Encoder().encode(buffer);
    }
    public static  void decodeBase64File(String base64Encode,String targetPath) throws Exception{
        byte[] buffer = new BASE64Decoder().decodeBuffer(base64Encode);
        FileOutputStream outputStream = new FileOutputStream(targetPath);
        outputStream.write(buffer);
        outputStream.close();
    }
    public static void main(String[] args) throws Exception {
        String base64Code = encodeBase64File("cc7.ser");
        System.out.println(base64Code);
    }
}

image.png

然后我们对base64编码的二进制文件,base64解码还原来比较一下sha256

// Base64EncodeTest
//...
public static void main(String[] args) throws Exception {
    String base64Code = encodeBase64File("cc7.ser");
    decodeBase64File(base64Code,"cc7base64Decode.ser");
}

image.png

可以发现是hash之后是相等的,那么最后需要更改的就是web接收的参数,为base64字符串,这个字符串当解码之后就是二进制流,需要存放在一个byte数组中,然后再存放在ByteArrayInputStream中,然后使用ObjectInputStream来读取,最后再readObject进行反序列化

byte[] buff = new BASE64Decoder().decodeBuffer(request.getParameter("data"));
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buff);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
objectInputStream.readObject();

完整的Spring web Controller 如下,对应的接口为/ysoserialBase64

package com.spring.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;

import java.io.*;
import javax.servlet.http.HttpServletRequest;

@Controller
public class HelloController {
    @RequestMapping(value = "/hi")
    public String ReturnJsp(){
        return "hello";
    }
    @RequestMapping(value = "/ysoserial")
    public String SerialTest(@RequestParam("file") MultipartFile f1) throws Exception{
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(f1.getBytes());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        return "test";
    }
    @RequestMapping(value = "/ysoserialBase64")
    public String SerialBase64Test(HttpServletRequest request) throws IOException, ClassNotFoundException {
        byte[] buff = new BASE64Decoder().decodeBuffer(request.getParameter("data"));
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(buff);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        objectInputStream.readObject();
        return "test";
    }
}

在进行传输base64编码的时候,一定要注意,因为base64编码存在+,在web进行传输的时候+会被解码成空格则会导致解码失败,详情参考Base64编码/解码原理在这里需要将base64编码再进行一次URL编码放在burp里传输,如下所示

image.png

image.png

相关问题

0x1 接收POST Body

最开始想如Adobe ColdFusion AMF Deserialization Remote Command Execution (CVE-2017-3066)的漏洞利用这样,将反序列化的数据保存到文本文件,然后直接pasted from burp,将文本文件的二进制流传递给web服务器,但是在我使用node.js的时候发现无法接收到来自POST的请求体,因为在express里要接收对应的POST Body,都是由中间件解析完成,然而其实并不想太麻烦,所以最后使用上传文件的方式来将二进制文件流传入给服务端,然后立马就有了编码问题

0x2 编码问题

我在反复尝试后,将经过网络传输的文件保存下来,再利用模拟的IO操作进行反序列化,发现一直无法反序列化成功,因为在模拟IO操作的地方,我发现有crash,CC2本身在反序列化cc2.ser的时候程序就会crash,然后一直没去调试反序列化的过程,在这里浪费了许多时间 排查思路,需要拿到对应的文件进行判断,是否正常 我在这里选择使用node.js,因为轻便(使用java也行,只是我用node比较快),简单来看一下问题

npm install express --save
npm install multer --save
const express = require('express')
const app = new express()
const fs = require('fs')
const multer = require('multer')
let multerConfig = multer({
  dest: './static/upload',
})

app.get('/',(req,res)=>{
    res.send('hahaha')
})

app.post('/',multerConfig.single('file'),(req,res)=>{
    console.log(req.file)
    res.send('get Post')
})

app.listen(8081,()=>{
    console.log('running!')
})

此时通过burp构造一个multipart/form-data,然后对应将cc2.ser 粘贴到burp里 image.png

image.png

对其进行sha256,与源文件进行对比,发现并不能对上

image.png

并且可以看到如下对比,通过pasted from burp 上传到的文件,已经不符合java 序列化文件的类型了

image.png

image.png

那到底为什么会出现这种情况?我在Adobe ColdFusion AMF Deserialization Remote Command Execution (CVE-2017-3066)复现过程遇到过,以前是用低版本burp能复现成功,最开始的时候没有探讨原因,后面在北京的时候问过大佬,说是因为编码问题,只要更改为utf-8就可以了,但是我把所有的编码方式都修改了,发现还是不行,包括还是修改对应的16进制码(只修改了一部分),还是不行 然后写了一个静态页面,上传页面,注意后端需要修改同源策略,允许跨域访问

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
</head>
<body>
    <form action="http://127.0.0.1:8081/" method="post" enctype="multipart/form-data">
        <input type="file" name="file">
        <input type="submit" name="submit">
    </form>
</body>
</html>
const express = require('express')
const app = new express()
const fs = require('fs')
const multer = require('multer')
let multerConfig = multer({
  dest: './static/upload',
})

app.all('*', function(req, res, next) {
  res.header('Access-Control-Allow-Origin', req.headers.origin) //需要显示设置来源
  // 'Access-Control-Allow-Headers', 'Content-Type'
  res.header(
    'Access-Control-Allow-Headers',
    'Origin, X-Requested-With, Content-Type, Accept, Authorization'
  )
  res.header('Access-Control-Allow-Methods', 'POST,GET,DELETE,OPTIONS')
  res.header('Access-Control-Allow-Credentials', true) //带cookies7
  res.header('Content-Type', 'application/json;charset=utf-8')

  if (req.method == 'OPTIONS') {
    res.sendStatus(200)
  } else {
    next()
  }
})

app.get('/',(req,res)=>{
    res.send('hahaha')
})

app.post('/',multerConfig.single('file'),(req,res)=>{
    console.log(req.file)
    res.send('get Post')
})

app.listen(8081,()=>{
    console.log('running!')
})

在此处上传文件发现,通过前端上传的文件,和源文件能相对应上

image.png

然后将两个包进行比较,发现序列化数据发生改变了,暂时还不知道如何解决,就是编码问题,从文件里获取的时候,文件内容其实就已经发生了变化 image.png

0x3 依赖

在CC链中,我们知道需要特定版本的Commons Collections才能触发反序列化的点,比如Commons Collections 1 需要配合使用JDK1.7 和 Commons Collections 3.1-3.2.1,然而当我直接把本地的jar包放上去之后,调试的时候竟然发现找不到对应的类,这个问题也是搞了好久才发现,一直以为是哪个环节出了问题,最后在pom.xml中引入Commons Collections 组件解决问题

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-collections4</artifactId>
  <version>4.0</version>
</dependency>
<dependency>
  <groupId>commons-collections</groupId>
  <artifactId>commons-collections</artifactId>
  <version>3.1</version>
</dependency>

参考链接

https://zhuanlan.zhihu.com/p/386631799

Adobe ColdFusion AMF Deserialization Remote Command Execution (CVE-2017-3066)

Copyright © aaron 2023 all right reserved,powered by Gitbook该文章修订时间: 2023-08-26 20:47:10

results matching ""

    No results matching ""